package com.pallass.config;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.header.HeaderWriter;
import org.springframework.security.web.header.HeaderWriterFilter;

import com.pallass.admin.domain.SysResource;
import com.pallass.security.service.CustomerUserDetailsService;

/**
 * 系统安全配置
 * 
 * @author Houor
 *
 * @createTime: 2017-02-27 10:46
 */
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	private static Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);

	@Autowired
	CustomerUserDetailsService userDetailsService;

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		List<SysResource> rList = userDetailsService.obtainResourceList();

		ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry eiur = null;
		eiur = http.formLogin().loginPage("/login").defaultSuccessUrl("/index").and().logout().logoutSuccessUrl("/login").and().authorizeRequests();

		// Add antMatchers from resource in database
		for (SysResource resource : rList) {
			if (resource.getResourceUrl() != null) {
				logger.debug("Add antMatchers {} with Authority {}", resource.getResourceUrl(), Arrays.toString(resource.getPermissions().split(",")));
				eiur.antMatchers(resource.getResourceUrl()).hasAnyAuthority(resource.getPermissions().trim().split(","));
			}
		}

		// .antMatchers("/login").permitAll()
		// .antMatchers("/admin/user/index").hasAnyAuthority("ADMIN")
		// .antMatchers("/admin/user/update").hasAnyAuthority("USER")
		// .anyRequest().authenticated()

		eiur.antMatchers("/index").authenticated();

		eiur.and().exceptionHandling().accessDeniedPage("/accessDenied");

		http.rememberMe().tokenValiditySeconds(60);
		// http.sessionManagement().sessionFixation().changeSessionId().maximumSessions(1).maxSessionsPreventsLogin(true).expiredUrl("/login");
		http.sessionManagement().invalidSessionUrl("/login").maximumSessions(1);

		http.csrf().disable();

		http.headers().disable();
		HeaderWriter headerWriter = new HeaderWriter() {
			public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
				response.setHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
				response.setHeader("Expires", "0");
				response.setHeader("Pragma", "no-cache");
				response.setHeader("X-Frame-Options", "SAMEORIGIN");
				response.setHeader("X-XSS-Protection", "1; mode=block");
				response.setHeader("x-content-type-options", "nosniff");
			}
		};
		List<HeaderWriter> headerWriterFilterList = new ArrayList<>();
		headerWriterFilterList.add(headerWriter);
		HeaderWriterFilter headerFilter = new HeaderWriterFilter(headerWriterFilterList);
		http.addFilter(headerFilter);
	}

	@Override
	public void configure(WebSecurity webSecurity) throws Exception {
		webSecurity.ignoring().antMatchers("/public/**", "/css/**", "/js/**");
		super.configure(webSecurity);
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());

		/*
		 * With method authenticationProvider enable user to login by password
		 * or password plain text
		 * 
		 * auth.authenticationProvider(authenticationProvider());
		 */

		// If add super statement, the password encoder will invalid
		// super.configure(auth);
	}

	/**
	 * Set Password Encoder
	 * 
	 * If use this way, the user can login by password or password plain text
	 * 
	 * @return
	 */
	protected DaoAuthenticationProvider authenticationProvider() {
		DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
		authenticationProvider.setUserDetailsService(userDetailsService);
		authenticationProvider.setPasswordEncoder(passwordEncoder());
		return authenticationProvider;
	}

	private PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

}
